#ifndef BASE_H
#define BASE_H

#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>

#include "base/macro_def.h"
#include "base/scoped_ptr.h"
#include "base/scoped_ref.h"
#include "scoped_ref.h"
#include "base/disk_file.h"
#include "base/file_util.h"

#include "base/thread.h"
#include "base/thread_util.h"

class AutoRunner {
  public:
    AutoRunner(Closure* c)
        : closure_(c) {
    }
    ~AutoRunner() {
      if (closure_ != NULL) {
        closure_->Run();
      }
    }

    Closure* release() {
      Closure* tmp = closure_;
      closure_ = NULL;
      return tmp;
    }

  private:
    Closure* closure_;

    DISALLOW_COPY_AND_ASSIGN(AutoRunner);
};

#define MIN_TASK_SIZE 1024

class TaskQueue : public Closure {
  public:
    TaskQueue(uint32 capacity)
        : capacity_(capacity < MIN_TASK_SIZE ? MIN_TASK_SIZE : capacity_) {
    }

    ~TaskQueue() {
      cond_.Signal();
      thread_.reset();
      CHECK(tasks_.empty());
    }

    bool Push(Closure* c) {
      ScopedMutex l(&lock_);
      if (tasks_.size() >= capacity_) {
        return false;
      }
      tasks_.push_back(c);

      cond_.Signal();
      return true;
    }

    void Run() {
      thread_.reset(
          new StopableThread(NewPermanentCallback(this, &TaskQueue::TaskLoop)));
      CHECK(thread_->Start());
    }

  private:
    uint32 capacity_;

    Mutex lock_;
    SyncEvent cond_;
    std::deque<Closure*> tasks_;

    scoped_ptr<StopableThread> thread_;
    void TaskLoop() {
      cond_.TimeWait(3 * 1000);
      std::deque<Closure*> holder;
      {
        ScopedMutex l(&lock_);
        tasks_.swap(holder);
      }

      while (!holder.empty()) {
        Closure* c = holder.front();
        holder.pop_front();
        c->Run();
      }

    }

    DISALLOW_COPY_AND_ASSIGN(TaskQueue);
};

#endif
